﻿using System;
using System.Linq;
using System.Collections.Generic;
using System.Text;
using Microsoft.WindowsMobile.Status;

namespace Senthil.Mobile.WhereAmI
{
    public class NotificationManager
    {
        private Dictionary<string, Func<NotificationTrigger, bool>> userPredicateMap = new Dictionary<string, Func<NotificationTrigger, bool>>();

        string ownerName;
        IRouteTracker tracker;
        IInputMessageReceiver receiver;
        INotifier notifier;

        public NotificationManager(string ownerName, IInputMessageReceiver receiver, INotifier notifier)
        {
            this.ownerName = ownerName;
            this.notifier = notifier;
            this.receiver = receiver;

            this.receiver.InputMessageReceived += new EventHandler<InputMessageReceivedEventArgs>(receiver_InputMessageReceived);
        }

        public NotificationManager(string ownerName, IRouteTracker tracker, IInputMessageReceiver receiver, INotifier notifier) : this(ownerName, receiver, notifier)
        {
            this.RouteTracker = tracker;
        }

        public void Enable()
        {
            receiver.Enable();
        }

        public void Disable()
        {
            receiver.Disable();
        }

        void receiver_InputMessageReceived(object sender, InputMessageReceivedEventArgs e)
        {
            if (tracker == null)
                return;

            NotificationTrigger trigger = new NotificationTrigger() { InputMessageReceived = e };
            ProcessTrigger(trigger);
        }

        public void NotifyUserWhenSMSInput(string[] users, string smsText)
        {
            foreach (string user in users)
            {
                if (string.IsNullOrEmpty(user))
                    continue;

                string localUser = user;
                userPredicateMap[user] = (trigger) => trigger.InputMessageReceived.From.Contains(localUser) && trigger.InputMessageReceived.Message == smsText;
            }

            receiver.ReceiveOnlyMessage(smsText);
        }

        public void NotifyUserWhenLocationReached(string[] users, Location location)
        {
            foreach (string user in users)
            {
                userPredicateMap[user] = (trigger) => location == trigger.NewLocation;
            }
        }

        public IRouteTracker RouteTracker
        {
            get { return tracker; }
            set { tracker = value; }
        }

        private void ProcessTrigger(NotificationTrigger trigger)
        {
            List<string> usersToNotify = new List<string>();

            foreach (var pair in userPredicateMap)
            {
                if (pair.Value(trigger))
                {
                    usersToNotify.Add(pair.Key);
                }
            }

            if (usersToNotify.Count == 0)
                return;

            var message = GetMessage();

            if (message != null)
                notifier.Notify(usersToNotify.ToArray(), message);
        }

        private NotificationMessage GetMessage()
        {
            Location lastKnownLocation;
            TimeSpan lastKnownTimeSpanToDestination;

            tracker.GetLastKnownInfo(out lastKnownLocation, out lastKnownTimeSpanToDestination);

            if (lastKnownLocation == null)
                return null;

            return new NotificationMessage()
            {
                OwnerName = ownerName,
                LocationName = lastKnownLocation.Name,
                LocationGroupName = lastKnownLocation.IsRecognized ? lastKnownLocation.LocationGroup.Name : null,
                DestinationLocationGroupName = tracker.DestinationLocationGroup.Name,
                DestinationTimeSpan = lastKnownTimeSpanToDestination,
                DestinationTime = DateTime.Now.Add(lastKnownTimeSpanToDestination)
            };
            
        }

        class NotificationTrigger
        {
            public InputMessageReceivedEventArgs InputMessageReceived { get; set; }
            public Location NewLocation { get; set; }
        }
    }
}
